package cc.sunni.admin.controller;

import cc.sunni.admin.service.AdminUserService;
import cc.sunni.api.BaseController;
import cc.sunni.api.controller.admin.AdminMngControllerApi;
import cc.sunni.api.utils.PageUtils;
import cc.sunni.api.utils.Query;
import cc.sunni.common.Constant;
import cc.sunni.common.enums.FaceVerifyType;
import cc.sunni.common.exception.RRException;
import cc.sunni.common.utils.FaceVerifyUtils;
import cc.sunni.common.utils.R;
import cc.sunni.common.utils.RedisOperator;
import cc.sunni.common.utils.ResultEnum;
import cc.sunni.pojo.AdminUser;
import cc.sunni.pojo.bo.AdminLoginBO;
import cc.sunni.pojo.bo.NewAdminBO;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@RestController
public class AdminMngController extends BaseController implements AdminMngControllerApi {
    @Autowired
    private RedisOperator redis;
    @Autowired
    private AdminUserService adminUserService;
    @Autowired
    private FaceVerifyUtils faceVerifyUtils;

    @Override
    public R adminLogin(AdminLoginBO adminLoginBO, HttpServletRequest request, HttpServletResponse response) {
        // 1. 查询admin用户的信息
        AdminUser admin = adminUserService.queryAdminByUsername(adminLoginBO.getUsername());
        // 2. 判断admin不为空，如果为空则登录失败
        if (admin == null) {
            return R.en(ResultEnum.ADMIN_NOT_EXIT_ERROR);
        }

        // 3. 判断密码是否匹配
        boolean isPwdMatch = BCrypt.checkpw(adminLoginBO.getPassword(), admin.getPassword());
        if (isPwdMatch) {
            doLoginSettings(admin, request, response);
            return R.ok();
        } else {
            return R.en(ResultEnum.ADMIN_NOT_EXIT_ERROR);
        }
    }

    /**
     * 用于admin用户登录过后的基本信息设置
     */
    private void doLoginSettings(AdminUser admin, HttpServletRequest request, HttpServletResponse response) {
        // 保存token放入到redis中
        String token = UUID.randomUUID().toString();
        redis.set(Constant.REDIS_ADMIN_TOKEN + ":" + admin.getId(), token);

        // 保存admin登录基本token信息到cookie中
        setCookie(request, response, "atoken", token, Constant.COOKIE_MONTH);
        setCookie(request, response, "aid", admin.getId(), Constant.COOKIE_MONTH);
        setCookie(request, response, "aname", admin.getUsername(), Constant.COOKIE_MONTH);
    }

    @Override
    public R adminIsExist(String username) {
        checkAdminExist(username);
        return R.ok();
    }

    private void checkAdminExist(String username) {
        AdminUser admin = adminUserService.queryAdminByUsername(username);
        if (admin != null) {
            throw new RRException(ResultEnum.ADMIN_USERNAME_EXIST_ERROR);
        }
    }

    @Override
    public R addNewAdmin(NewAdminBO newAdminBO, HttpServletRequest request, HttpServletResponse response) {
        // 1. base64不为空，则代表人脸入库，否则需要用户输入密码和确认密码
        if (StrUtil.isBlank(newAdminBO.getImg64())) {
            if (StrUtil.isBlank(newAdminBO.getPassword()) || StrUtil.isBlank(newAdminBO.getConfirmPassword())) {
                return R.en(ResultEnum.ADMIN_PASSWORD_NULL_ERROR);
            }
        }

        // 2. 密码不为空，则必须判断两次输入一致
        if (StrUtil.isNotBlank(newAdminBO.getPassword())) {
            if (!newAdminBO.getPassword().equalsIgnoreCase(newAdminBO.getConfirmPassword())) {
                return R.en(ResultEnum.ADMIN_PASSWORD_ERROR);
            }
        }

        // 3. 校验用户名唯一
        checkAdminExist(newAdminBO.getUsername());

        // 4. 调用service存入admin信息
        adminUserService.createAdminUser(newAdminBO);
        return R.ok();
    }

    @Override
    public R getAdminList(Integer page, Integer pageSize) {
//        PagedGridResult result = adminUserService.queryAdminList(page, pageSize);
        Map<String, Object> params = new HashMap<>();
        params.put(Query.PAGE_NO, page);
        params.put(Query.SIZE, pageSize);
        PageUtils pageUtils = adminUserService.queryPage(params);
        return R.ok(pageUtils);
    }

    @Override
    public R adminLogout(String adminId, HttpServletRequest request, HttpServletResponse response) {
        // 从redis中删除admin的会话token
        redis.del(Constant.REDIS_ADMIN_TOKEN + ":" + adminId);

        // 从cookie中清理adming登录的相关信息
        deleteCookie(request, response, "atoken");
        deleteCookie(request, response, "aid");
        deleteCookie(request, response, "aname");
        return R.ok();
    }

    @Override
    public R adminFaceLogin(AdminLoginBO adminLoginBO, HttpServletRequest request, HttpServletResponse response) {
        // 0. 判断用户名和人脸信息不能为空
        if (StrUtil.isBlank(adminLoginBO.getUsername())) {
            return R.en(ResultEnum.ADMIN_USERNAME_NULL_ERROR);
        }
        String tempFace64 = adminLoginBO.getImg64();
        if (StrUtil.isBlank(tempFace64)) {
            return R.en(ResultEnum.ADMIN_FACE_NULL_ERROR);
        }
        // 1. 从数据库中查询出faceId
        AdminUser admin = adminUserService.queryAdminByUsername(adminLoginBO.getUsername());
        String adminFaceId = admin.getFaceId();
        if (StrUtil.isBlank(adminFaceId)) {
            return R.en(ResultEnum.ADMIN_FACE_NOT_REGISTER);
        }
        // 2. 请求文件服务，获得人脸数据的base64数据
        String fileServerUrlExecute = "http://files.imoocnews.com:8004/fs/readFace64InGridFS?faceId=" + adminFaceId;
        String respone = HttpUtil.get(fileServerUrlExecute);
        R bodyResult = JSONUtil.toBean(respone, R.class);
        String base64DB = (String) bodyResult.get("data");
        // 3. 调用阿里ai进行人脸对比识别，判断可信度，从而实现人脸登录
        boolean result = faceVerifyUtils.faceVerify(FaceVerifyType.BASE64.type, tempFace64, base64DB, 80);

        if (!result) {
            return R.en(ResultEnum.ADMIN_FACE_LOGIN_ERROR);
        }

        // 4. admin登录后的数据设置，redis与cookie
        doLoginSettings(admin, request, response);
        return R.ok();
    }
}
